unit vector2;

{$mode objfpc}{$H+}{$J-} {$modeSwitch advancedRecords}
interface

uses Math, SysUtils, Classes;

type
  
  TVectorTuple2 = record
    x1, x2, y1, y2: single;
    class operator = (const v1, v2: TVectorTuple2): boolean; inline;
  end;
  PTVector2 = ^TVector2;
  TVector2 = record
  public
    x, y: single;
    procedure Normalize();
    function Length(): single;
    class operator +(const v1, v2: TVector2): TVector2; inline;
    class operator +(v: TVector2; z: single): TVector2; inline;
  //class operator + (z:single;v:TVector2):TVector2;inline;
    class operator -(const v1, v2: TVector2): TVector2; inline;
  //class operator - (const v:TVector2):TVector2;inline;
    class operator * (v: TVector2; z: single): TVector2; inline;
    class operator / (v: TVector2; z: single): TVector2; inline;
    class operator = (const v1, v2: TVector2): boolean; inline;
    class function Equals(const V1, V2: TVector2): boolean; overload; inline; static;
    class function Equals(const V1, V2: TVector2; const Epsilon: single): boolean;
        overload; inline; static;
    function ToString: string;
    function IsZero: boolean;

  end;

function lerp(a, b, t:single):single;


implementation

function lerp(a, b, t:single):single;
begin
  result := (1-t)*a + t*b;
end;
function TVector2.ToString: string;
begin
  Result := Format('%f %f', [x, y]);
end;

class operator TVector2. * (v: TVector2; z: single): TVector2; inline;
begin
  Result.x := v.x * z;
  Result.y := v.y * z;
end;

class operator TVectorTuple2. = (const v1, v2: TVectorTuple2): boolean; inline;
begin
  Result := SameValue(v1.x1, v2.x1) and SameValue(v1.x2, v2.x2) and
    SameValue(v1.y1, v2.y1) and SameValue(v1.y2, v2.y2);
end;

class operator TVector2. = (const v1, v2: TVector2): boolean; inline;
begin
  Result := TVector2.Equals(v1, v2);
end;

class function TVector2.Equals(const V1, V2: TVector2): boolean;
begin
  Result :=
    SameValue(V1.x, V2.x) and SameValue(V1.y, V2.y);
end;

class function TVector2.Equals(const V1, V2: TVector2; const Epsilon: single): boolean;
begin
  if Epsilon = 0 then
    Result := (V1.x = V2.x) and (V1.y = V2.y)
  else
    Result := (Abs(V1.x - V2.x) < Epsilon) and (Abs(V1.y - V2.y) < Epsilon);

end;

function TVector2.IsZero: boolean;
begin
  Result := Math.IsZero(x) and Math.IsZero(y);
end;

class operator TVector2. -(const v1, v2: TVector2): TVector2; inline;
begin
  Result.x := v1.x - v2.x;
  Result.y := v1.y - v2.y;
end;

class operator TVector2. +(v: TVector2; z: single): TVector2;
begin
  //result := TVector2.Create;
  Result.x := v.x + z;
  Result.y := v.y + z;
end;

class operator TVector2. +(const v1, v2: TVector2): TVector2;
begin
  //result := TVector2.Create;
  Result.x := v1.x + v2.x;
  Result.y := v1.y + v2.y;
end;

class operator TVector2. / (v: TVector2; z: single): TVector2;
begin
  //result := TVector2.Create;
  Result.x := v.x / z;
  Result.y := v.y / z;
end;

procedure TVector2.Normalize();
var
  l: single;
begin
  l := length();
  if l > 0 then
    self := self / l;
end;

function TVector2.Length(): single;
begin
  Result := sqrt(x * x + y * y);
end;

end.
